1 /* 2 * Collie - An asynchronous event-driven network framework using Dlang development 3 * 4 * Copyright (C) 2015-2017 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: putao's Dlang team 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 module collie.codec.http.parser.parsertype; 12 13 enum HTTPParserType 14 { 15 HTTP_REQUEST, 16 HTTP_RESPONSE, 17 HTTP_BOTH 18 } 19 20 21 enum HTTPParserErrno 22 { 23 /* No error */ 24 HPE_OK = 0, //"success") \ 25 26 /* Callback-related errors */ 27 HPE_CB_MessageBegin = 1, //"the on_message_begin callback failed") \ 28 HPE_CB_Url = 2, // "the on_url callback failed") \ 29 HPE_CB_HeaderField = 3, //"the on_header_field callback failed") \ 30 HPE_CB_HeaderValue = 4, //"the on_header_value callback failed") \ 31 HPE_CB_HeadersComplete = 5, //"the on_headers_complete callback failed") \ 32 HPE_CB_Body = 6, //"the on_body callback failed") \ 33 HPE_CB_MessageComplete = 7, // "the on_message_complete callback failed") \ 34 HPE_CB_Status = 8, // "the on_status callback failed") \ 35 HPE_CB_ChunkHeader = 9, //"the on_chunk_header callback failed") \ 36 HPE_CB_ChunkComplete = 10, //"the on_chunk_complete callback failed") \ 37 38 /* Parsing-related errors */ 39 HPE_INVALID_EOF_STATE = 11, // "stream ended at an unexpected time") \ 40 HPE_HEADER_OVERFLOW = 12, // "too many header bytes seen; overflow detected") \ 41 HPE_CLOSED_CONNECTION = 13, // "data received after completed connection: close message") \ 42 HPE_INVALID_VERSION = 14, // "invalid HTTP version") \ 43 HPE_INVALID_STATUS = 15, //"invalid HTTP status code") \ 44 HPE_INVALID_METHOD = 16, //"invalid HTTP method") \ 45 HPE_INVALID_URL = 17, //"invalid URL") \ 46 HPE_INVALID_HOST = 18, //"invalid host") \ 47 HPE_INVALID_PORT = 19, //"invalid port") \ 48 HPE_INVALID_PATH = 20, //"invalid path") \ 49 HPE_INVALID_QUERY_STRING = 21, //"invalid query string") \ 50 HPE_INVALID_FRAGMENT = 22, // "invalid fragment") \ 51 HPE_LF_EXPECTED = 23, //"LF character expected") \ 52 HPE_INVALID_HEADER_TOKEN = 24, //"invalid character in header") \ 53 HPE_INVALID_CONTENT_LENGTH = 25, // "invalid character in content-length header") \ 54 HPE_UNEXPECTED_CONTENT_LENGTH = 26, // "unexpected content-length header") \ 55 HPE_INVALID_CHUNK_SIZE = 27, // "invalid character in chunk size header") \ 56 HPE_INVALID_CONSTANT = 28, // "invalid constant string") \ 57 HPE_INVALID_INTERNAL_STATE = 29, //"encountered unexpected internal state")\ 58 HPE_STRICT = 30, // "strict mode assertion failed") \ 59 HPE_PAUSED = 31, //"parser is paused") \ 60 HPE_UNKNOWN = 32 //"an unknown error occurred") 61 } 62 63 package (collie.codec.http) : 64 65 enum CR = '\r'; 66 enum LF = '\n'; 67 68 enum ubyte[] PROXY_CONNECTION = cast(ubyte[]) "proxy-connection"; 69 enum ubyte[] CONNECTION = cast(ubyte[]) "connection"; 70 enum ubyte[] CONTENT_LENGTH = cast(ubyte[]) "content-length"; 71 enum ubyte[] TRANSFER_ENCODING = cast(ubyte[]) "transfer-encoding"; 72 enum ubyte[] UPGRADE = cast(ubyte[]) "upgrade"; 73 enum ubyte[] CHUNKED = cast(ubyte[]) "chunked"; 74 enum ubyte[] KEEP_ALIVE = cast(ubyte[]) "keep-alive"; 75 enum ubyte[] CLOSE = cast(ubyte[]) "close"; 76 77 enum ULLONG_MAX = ulong.max; 78 79 enum string[33] error_string = [ 80 "success" //ok 81 /* Callback-related errors */ 82 , "the on_message_begin callback failed" //CB_message_begin 83 , 84 "the on_url callback failed" //CB_url 85 , "the on_header_field callback failed" //CB_header_field 86 , 87 "the on_header_value callback failed" //CB_header_value 88 , "the on_headers_complete callback failed" //CB_headers_complete 89 , "the on_body callback failed" //CB_body 90 , 91 "the on_message_complete callback failed" //CB_message_complete 92 , "the on_status callback failed" //CB_status 93 , "the on_chunk_header callback failed" //CB_chunk_header 94 , 95 "the on_chunk_complete callback failed" //CB_chunk_complete 96 /* Parsing-related errors */ 97 , "stream ended at an unexpected time" //INVALID_EOF_STATE 98 , 99 "too many header bytes seen; overflow detected" //HEADER_OVERFLOW 100 , "data received after completed connection: close message" //CLOSED_CONNECTION 101 , 102 "invalid HTTP version" //INVALID_VERSION 103 , "invalid HTTP status code" //INVALID_STATUS 104 , "invalid HTTP method" //INVALID_METHOD 105 , "invalid URL" //INVALID_URL 106 , 107 "invalid host" //INVALID_HOST 108 , "invalid port" // INVALID_PORT 109 , "invalid query string" //INVALID_QUERY_STRING 110 , "invalid fragment" //INVALID_FRAGMENT 111 , 112 "LF character expected" //LF_EXPECTED 113 , "invalid character in header" //INVALID_HEADER_TOKEN 114 , 115 "invalid character in content-length header" //INVALID_CONTENT_LENGTH 116 , "unexpected content-length header" // UNEXPECTED_CONTENT_LENGTH 117 , 118 "invalid character in chunk size header" //INVALID_CHUNK_SIZE 119 , "invalid constant string" //INVALID_CONSTANT 120 , "encountered unexpected internal state" //INVALID_INTERNAL_STATE 121 , 122 "strict mode assertion failed" // STRICT 123 , "parser is paused" //PAUSED 124 , "an unknown error occurred" //UNKNOWN 125 ]; 126 127 enum HTTPParserFlags 128 { 129 F_CHUNKED = 1 << 0, 130 F_CONNECTION_KEEP_ALIVE = 1 << 1, 131 F_CONNECTION_CLOSE = 1 << 2, 132 F_CONNECTION_UPGRADE = 1 << 3, 133 F_TRAILING = 1 << 4, 134 F_UPGRADE = 1 << 5, 135 F_SKIPBODY = 1 << 6, 136 F_CONTENTLENGTH = 1 << 7, 137 F_ZERO = 0 138 } 139 140 enum HTTPParserURLFields 141 { 142 UF_SCHEMA = 0, 143 UF_HOST = 1, 144 UF_PORT = 2, 145 UF_PATH = 3, 146 UF_QUERY = 4, 147 UF_FRAGMENT = 5, 148 UF_USERlogInfo = 6, 149 UF_MAX = 7 150 } 151 152 __gshared static const char[256] tokens = [ /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 153 0, 0, 0, 0, 0, 0, 0, 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 154 0, 0, 0, 0, 0, 0, 0, 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 155 0, 0, 0, 0, 0, 0, 0, 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 156 0, 0, 0, 0, 0, 0, 0, 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 157 0, '!', 0, '#', '$', '%', '&', '\'', /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 158 0, 0, '*', '+', 0, '-', '.', 0, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ 159 '0', 160 '1', '2', '3', '4', '5', '6', '7', /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ 161 '8', '9', 0, 0, 0, 0, 0, 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 162 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 163 'h', 'i', 164 'j', 'k', 'l', 'm', 'n', 'o', /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 165 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 166 'x', 167 'y', 'z', 0, 0, 0, '^', '_', /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ 168 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 169 'h', 170 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 171 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 172 /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 173 'x', 'y', 'z', 0, '|', 0, '~', 0]; 174 175 __gshared static const byte[256] unhex = [-1, -1, -1, -1, -1, -1, -1, 176 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 177 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 178 -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, 179 -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, 180 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 181 -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 182 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]; 183 184 version (HTTP_PARSER_STRICT) 185 { 186 pragma(inline,true) 187 ubyte T(ubyte v) 188 { 189 return 0; 190 } 191 } 192 else 193 { 194 pragma(inline,true) 195 ubyte T(ubyte v) 196 { 197 return v; 198 } 199 } 200 201 __gshared const ubyte[32] normal_url_char = [ /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 202 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 203 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 204 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 205 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 206 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 207 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ 208 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ 209 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 210 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 211 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 212 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 213 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ 214 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 215 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 216 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 217 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,]; 218 219 enum HTTPParserState 220 { 221 s_dead = 1 /* important that this is > 0 */ 222 223 , 224 s_start_req_or_res, 225 s_res_or_resp_H, 226 s_start_res, 227 s_res_H, 228 s_res_HT, 229 s_res_HTT, 230 s_res_HTTP, 231 s_res_first_http_major, 232 s_res_http_major, 233 s_res_first_http_minor, 234 s_res_http_minor, 235 s_res_first_status_code, 236 s_res_status_code, 237 s_res_status_start, 238 s_res_status, 239 s_res_line_almost_done, 240 s_start_req, 241 s_req_method, 242 s_req_spaces_before_url, 243 s_req_schema, 244 s_req_schema_slash, 245 s_req_schema_slash_slash, 246 s_req_server_start, 247 s_req_server, 248 s_req_server_with_at, 249 s_req_path, 250 s_req_query_string_start, 251 s_req_query_string, 252 s_req_fragment_start, 253 s_req_fragment, 254 s_req_http_start, 255 s_req_http_H, 256 s_req_http_HT, 257 s_req_http_HTT, 258 s_req_http_HTTP, 259 s_req_first_http_major, 260 s_req_http_major, 261 s_req_first_http_minor, 262 s_req_http_minor, 263 s_req_line_almost_done, 264 s_header_field_start, 265 s_header_field, 266 s_header_value_discard_ws, 267 s_header_value_discard_ws_almost_done, 268 s_header_value_discard_lws, 269 s_header_value_start, 270 s_header_value, 271 s_header_value_lws, 272 s_header_almost_done, 273 s_chunk_size_start, 274 s_chunk_size, 275 s_chunk_parameters, 276 s_chunk_size_almost_done, 277 s_headers_almost_done, 278 s_headers_done /* Important: 's_headers_done' must be the last 'header' state. All 279 * states beyond this must be 'body' states. It is used for overflow 280 * checking. See the PARSING_HEADER() macro. 281 */ 282 283 , 284 s_chunk_data, 285 s_chunk_data_almost_done, 286 s_chunk_data_done, 287 s_body_identity, 288 s_body_identity_eof, 289 s_message_done 290 } 291 292 enum HTTPParserHeaderstates 293 { 294 h_general = 0, 295 h_C, 296 h_CO, 297 h_CON, 298 h_matching_connection, 299 h_matching_proxy_connection, 300 h_matching_content_length, 301 h_matching_transfer_encoding, 302 h_matching_upgrade, 303 h_connection, 304 h_content_length, 305 h_transfer_encoding, 306 h_upgrade, 307 h_matching_transfer_encoding_chunked, 308 h_matching_connection_token_start, 309 h_matching_connection_keep_alive, 310 h_matching_connection_close, 311 h_matching_connection_upgrade, 312 h_matching_connection_token, 313 h_transfer_encoding_chunked, 314 h_connection_keep_alive, 315 h_connection_close, 316 h_connection_upgrade 317 } 318 319 enum HTTPParserHostState 320 { 321 s_http_host_dead = 1, 322 s_http_userlogInfo_start, 323 s_http_userlogInfo, 324 s_http_host_start, 325 s_http_host_v6_start, 326 s_http_host, 327 s_http_host_v6, 328 s_http_host_v6_end, 329 s_http_host_v6_zone_start, 330 s_http_host_v6_zone, 331 s_http_host_port_start, 332 s_http_host_port 333 }